﻿using System;
using System.Collections.Generic;
using System.Text;
using FenopyApi;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;

namespace FenopyApiTests
{
    [TestClass]
    public class FenopyClientTest
    {
        [TestMethod]
        [ExpectedException(typeof(Exception), AllowDerivedTypes = true)]
        public void SearchMega()
        {
            // Build a very large request
            StringBuilder sb = new StringBuilder();
            while (sb.Length <= 4096)
                for (int i = 0; i < 256; i++)
                    sb.Append((char)i);

            // It will crash, because fenopy server is unpredictable when faced with crap data
            List<SearchResult> results = FenopyClient.Search(sb.ToString());
        }

        [TestMethod]
        public void SearchNoResults()
        {
            List<SearchResult> results = FenopyClient.Search("a");

            Assert.AreEqual(0, results.Count);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException), AllowDerivedTypes = false)]
        public void FakeNullString()
        {
            string input = null;
            FenopyClient.IsFake(input);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException), AllowDerivedTypes = false)]
        public void FakeNullBytes()
        {
            byte[] input = null;
            FenopyClient.IsFake(input);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException), AllowDerivedTypes = false)]
        public void FakeLengthString()
        {
            string input = "..";
            FenopyClient.IsFake(input);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException), AllowDerivedTypes = false)]
        public void FakeLengthBytes()
        {
            byte[] input = new byte[10];
            FenopyClient.IsFake(input);
        }

        [TestMethod]
        public void SearchResults()
        {
            SearchResult res = new SearchResult();

            res.IsVerified = true;
            Assert.AreEqual(1, res.Verified);

            res.IsVerified = false;
            Assert.AreEqual(0, res.Verified);
        }

        [TestMethod]
        public void Fake()
        {
            // Ubuntu 10 04 LTS x64
            FakeResponse verified = FenopyClient.IsFake("82fda5df1c8294302ee97e973fad8dc54c75b13e");
            FakeResponse verified2 = FenopyClient.IsFake(new byte[] { 0x82, 0xfd, 0xa5, 0xdf, 0x1c, 0x82, 0x94, 0x30, 0x2e, 0xe9, 0x7e, 0x97, 0x3f, 0xad, 0x8d, 0xc5, 0x4c, 0x75, 0xb1, 0x3e });

            Assert.AreEqual(FakeResponse.Verified, verified);
            Assert.AreEqual(FakeResponse.Verified, verified2);

            // Review of Ubuntu
            FakeResponse unknown = FenopyClient.IsFake("10ed29916dfef7249c3cebbc3b6d3c01219b367d");

            Assert.AreEqual(FakeResponse.Neutral, unknown);

            // Fake torrent
            // I haven't found one yet
            Assert.Inconclusive("Missing test of fake torrent - the others work though");
        }

        [TestMethod]
        public void Search()
        {
            List<SearchResult> results = FenopyClient.Search("test");

            Assert.IsTrue(results.Any());

            // Assert all fields have info
            foreach (SearchResult result in results)
            {
                Assert.IsNotNull(result);

                Assert.IsNotNull(result.Name);
                Assert.IsNotNull(result.Page);
                Assert.IsNotNull(result.Torrent);
                Assert.IsNotNull(result.Magnet);
                Assert.IsNotNull(result.Hash);
                Assert.IsNotNull(result.Category);

                Assert.IsTrue(result.Size > 0);
                Assert.IsTrue((result.Verified == 0 && !result.IsVerified) || (result.Verified == 1 && result.IsVerified) || (result.Verified == 2 && result.IsVerified));

                // Difficult to test these two, as they vary by torrent
                Assert.IsTrue(result.Seeder >= 0);
                Assert.IsTrue(result.Leecher >= 0);
            }
        }

        [TestMethod]
        public void SearchLimit()
        {
            for (int i = 100; i >= 10; i -= 10)
            {
                List<SearchResult> results = FenopyClient.Search("star", i);
                Assert.IsTrue(results.Count == i);
            }

            // Bogus limit
            List<SearchResult> bogusResults = FenopyClient.Search("star", 0);
            Assert.IsTrue(bogusResults.Count != 0);
        }

        [TestMethod]
        public void SearchCategory()
        {
            List<SearchResult> results = FenopyClient.Search("prison break", 100, Category.TVShows);

            Assert.IsTrue(results.Count >= 2);
            Assert.IsTrue(results.All(s => s.Category == "TV Shows"));

            // Another one
            results = FenopyClient.Search("star", 100, Category.Video);

            Assert.IsTrue(results.Count >= 2);
            Assert.IsTrue(results.All(s => s.Category == "Videos"));

            // Bogus one
            results = FenopyClient.Search("star", 100, (Category)7000);

            Assert.IsTrue(results.Count >= 2);

            // Ensure we have multiple categories - proving category '7000' was not set
            Assert.IsTrue(results.Select(s => s.Category).Distinct().Count() >= 2);
        }

        [TestMethod]
        public void SearchOrdering()
        {
            List<SearchResult> results = FenopyClient.Search("ubuntu", 100, Category.All, Sorting.Size);

            Assert.IsTrue(results.Count >= 2);

            int wrongCount = 0;     // Fenopy has a glitch in their sorting of sizes. Test 100 results, and check that ~98% of them are correct instead.
            long[] sizes = results.Select(s => s.Size).ToArray();
            for (int i = 0; i < sizes.Length - 1; i++)
            {
                if (sizes[i] < sizes[i + 1])
                    // Size increased(!)
                    wrongCount++;
            }

            Assert.IsTrue(wrongCount <= 2);

            results = FenopyClient.Search("ubuntu", 100, Category.All, Sorting.Peer);

            Assert.IsTrue(results.Count >= 2);

            int[] peers = results.Select(s => s.Leecher + s.Seeder).ToArray();
            for (int i = 0; i < peers.Length - 1; i++)
            {
                Assert.IsTrue(peers[i] >= peers[i + 1]);
            }
        }
    }
}
